package com.gxa.weixing.portal.service.impl;


import com.gxa.weixing.core.common.ExceptionCode;
import com.gxa.weixing.core.exception.BusinessException;
import com.gxa.weixing.core.pojo.*;

import com.gxa.weixing.core.service.impl.BaseServiceImpl;
import com.gxa.weixing.core.util.JsonUtil;
import com.gxa.weixing.portal.mapper.ForGoodsMapper;
import com.gxa.weixing.portal.mapper.GoodsMapper;
import com.gxa.weixing.portal.mapper.UserExchangeMapper;
import com.gxa.weixing.portal.mapper.UserGoldMapper;
import com.gxa.weixing.portal.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;

/**
 * @Author HHT
 * 2022/1/6
 */
@Service
public class GoodsServiceImpl extends BaseServiceImpl<Goods> implements GoodsService {

    //商品列表
    public static final String GOODS="goodsList";
    //商品详情
    public static final String GOODDETAILE="GoodDetail";
    //购物车
    public static final String CART="cart";
    //兑换商品
    public static final String EXCHANGE="exchange";
    //兑换商品详情
    public static final String EXCHANGDTAILE="exchangeDetail";

    @Autowired
  private   RedisTemplate<String,Object> redisTemplate;

    @Autowired
    GoodsMapper goodsMapper;

    @Autowired
    ForGoodsMapper forGoodsMapper;

    @Autowired
    UserExchangeMapper userExchangeMapper;

    @Autowired
    UserGoldMapper userGoldMapper;
    @Override
    public List<Goods> findAll() {
        HashOperations<String, Object, Object> opsForHash = redisTemplate.opsForHash();
        //从存储商品hash中获取key为GOODS的值
        Map<Object, Object> entries = opsForHash.entries(GOODS);
       //如果为空（可能是第一次查询或访问），就从数据库把值拿到。
        if (entries.keySet().size()==0){
            List<Goods> goods = goodsMapper.selectAll();
            //把拿到的值添加到hash中
            for (Goods good : goods) {
                //把对象转化为字符串
                String string = JsonUtil.objectToString(good);
                opsForHash.put(GOODS,string,1);
            }
        }
        //再查询一次
        Map<Object, Object> entries1 = opsForHash.entries(GOODS);
        //新建一个list存放值
        List<Goods> list=new ArrayList<>();
        //得到hash的键，因为redis中的键存的是goods对象
        Set<Object> objects = entries1.keySet();
        for (Object object : objects) {
            //用JsonUtil把object转化为Good对象
            Goods goods = JsonUtil.stringToObject(object.toString(), Goods.class);
            list.add(goods);
        }
        return list;
    }

    @Override
    public GoodDetailVO selectById(Long id) {
        //先声明一个GoodDetailVO对象
        GoodDetailVO goodDetailVO=null;
        //声明redis的string数据类型对象
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
       //从redis中根据id获取商品详细信息的数据
        Object o = ops.get(GOODDETAILE+id);
        //如果不存在，说明是第一次查询，可以先从数据库中拿到数据，这里需不需要设置过期时间，还需考虑
       if (o==null){
           goodDetailVO=new GoodDetailVO();
           //获取数据库的数据
           List<Map<String, Object>> maps = goodsMapper.selectById(id);
           //再创建一个List集合，方便存入GoodDetailVO对象
           List<Imgs> list=new ArrayList<>();
           //遍历，把数据加入到GoodDetailVO对象中
           for (Map<String, Object> map : maps) {
               Imgs img=new Imgs();
               //先添加简单类型的数据
               goodDetailVO.setName(map.get("goods_name").toString());
               goodDetailVO.setDetailIntroduce(map.get("goods_detail_introduce").toString());
               goodDetailVO.setPrice(Double.valueOf(map.get("goods_price").toString()));
               goodDetailVO.setId(Long.valueOf(map.get("goods_id").toString()));
               goodDetailVO.setDetailSold(Integer.valueOf(map.get("goods_detail_sold").toString()));
               goodDetailVO.setDesc(map.get("goods_desc").toString());
               goodDetailVO.setDetailSampleImg(map.get("goods_detail_sample_img").toString());
               goodDetailVO.setDetailUnit(map.get("goods_detail_unit").toString());
               goodDetailVO.setPrePrice(Double.valueOf(map.get("goods_pre_price").toString()));
               //对VO的集合属性添加值
               img.setImg(map.get("img").toString());
               list.add(img);
           }
           //最后把list集合添加到VO对象中
           goodDetailVO.setGoodImg(list);
          //把VO对象转化为json字符串
           String vo = JsonUtil.objectToString(goodDetailVO);
           //添加到redis中
           ops.set(GOODDETAILE+id,vo);
       }else {
           //如果redis中存在数据，获取信息
           Object o1 = ops.get(GOODDETAILE + id);

           //转化为vo对象
           goodDetailVO = JsonUtil.stringToObject(o1.toString(), GoodDetailVO.class);

       }
        return goodDetailVO;
    }

    @Override
    public void addGoodToCart(Goods goods,Long id,Integer type) {
        //声明一个hash对象
        HashOperations<String, Object, Object> ops = redisTemplate.opsForHash();
        //把Goods对象转化为json字符串
        String stringGoods = JsonUtil.objectToString(goods);
        //用id作为hash键，Goods对象作为值存储在redis里面
        Boolean aBoolean = ops.putIfAbsent(CART + id, stringGoods, 1);
        //跟据返回值做分析，如果返回值为true，那么说明该商品是用户第一次加入购物车，到这里就已经把数据加入到redis中了，如果
        //返回值是false，那么说明用户已经将该物品加入过购物车了，只需要在原有的基础上在加1或者减1即可
        if (!aBoolean){
            if (type==1){
                ops.increment(CART+id,stringGoods,1);
            }
            if (type==0){
                ops.increment(CART+id,stringGoods,-1);
            }
        }
        //至此，分析完毕，需不需要在购物车考虑库存的问题，还要再考虑
    }

    @Override
    public List<GetGoodsFromCartVO> findAllFromCart(Long id) {

        //声明一个hash对象
        HashOperations<String, Object, Object> ops = redisTemplate.opsForHash();
        Map<Object, Object> entries = ops.entries(CART + id);
        //声明一个List,用于存储键值
        List<GetGoodsFromCartVO> list=new ArrayList<>();
        //获取hashkey
        Set<Object> objects = entries.keySet();
        //遍历，然后把hashkey转化为Good对象
        for (Object object : objects) {
            //声明一个VO对象
            GetGoodsFromCartVO getGoodsFromCartVO=new GetGoodsFromCartVO();
            Goods goods = JsonUtil.stringToObject(object.toString(), Goods.class);

            //向VO对象中赋值
            getGoodsFromCartVO.setId(goods.getId());
            getGoodsFromCartVO.setDesc(goods.getDesc());
            getGoodsFromCartVO.setImg(goods.getImg());
            getGoodsFromCartVO.setName(goods.getName());
            getGoodsFromCartVO.setPrePrice(goods.getPrePrice());
            getGoodsFromCartVO.setPrice(goods.getPrice());
            getGoodsFromCartVO.setPurchasePrice(goods.getPurchasePrice());
            getGoodsFromCartVO.setState(goods.getState());
            //获取最后一个属性值num,要先把goods转化为json字符串才能到redis中获取数据
            String string = JsonUtil.objectToString(goods);

            Object o = ops.get(CART + id, string);

            getGoodsFromCartVO.setNum(Integer.valueOf(o.toString()));
            list.add(getGoodsFromCartVO);
        }
        return list;
    }


    @Override
    public void deleteGoodFromCart(List<Long> list,Long userId) {
        //整体思路，先把数据取出来添加到map集合中，删除map集合中指定的元素，再整体删除redis中的数据，再添加
        //声明一个hash类型对象
        HashOperations<String, Object, Object> ops = redisTemplate.opsForHash();
        //获取一个map类型的键值
        Map<Object, Object> entries = ops.entries(CART + userId);
        //声明一个map对象，用于存储redis中的hash键值
        Map<Object, Object> map = new HashMap<>(entries);
        //获取map的键后遍历,这里需要注意不能用map的键去遍历，否则会引起并发异常!
        Set<Object> objects = entries.keySet();
        for (Object object : objects) {
            //把json字符串转化为good对象
            Goods goods = JsonUtil.stringToObject(object.toString(), Goods.class);
            //遍历list集合
            for (Long aLong : list) {
                //容易知道当list集合的id和goods的id相同就做删除操作，即移除map中的键值
                if (aLong.equals(goods.getId())){
                    String string = JsonUtil.objectToString(goods);
                    map.remove(string);
                }
            }
        }
        //此时，map中的键值已经是需要的数据,先删除redis中的数据
        redisTemplate.delete(CART+userId);
        //添加数据
        if (map.keySet().size()!=0){
            ops.putAll(CART+userId,map);
        }
    }

    /**
     * 这里操作和获取商品列表一样。不再赘述
     * @return
     */
    @Override
    public List<ForGoods> exchangeGoodsList() {
        HashOperations<String, Object, Object> opsForHash = redisTemplate.opsForHash();
        //从存储商品hash中获取key为GOODS的值
        Map<Object, Object> entries = opsForHash.entries(EXCHANGE);
        //如果为空（可能是第一次查询或访问），就从数据库把值拿到。
        if (entries.keySet().size()==0){
            List<ForGoods> goods = forGoodsMapper.selectAll();
            //把拿到的值添加到hash中
            for (ForGoods good : goods) {
                //把对象转化为字符串
                String string = JsonUtil.objectToString(good);
                opsForHash.put(EXCHANGE,string,1);
            }
        }
        //再查询一次
        Map<Object, Object> entries1 = opsForHash.entries(EXCHANGE);
        //新建一个list存放值
        List<ForGoods> list=new ArrayList<>();
        //得到hash的键，因为redis中的键存的是goods对象
        Set<Object> objects = entries1.keySet();
        for (Object object : objects) {
            //用JsonUtil把object转化为Good对象
            ForGoods goods = JsonUtil.stringToObject(object.toString(), ForGoods.class);
            list.add(goods);
        }
        return list;
    }

    @Override
    public ForGoodsDetailVo selectByIdForGoods(Long id) {
        //先声明一个GoodDetailVO对象
        ForGoodsDetailVo forGoodsDetailVo=null;
        //声明redis的string数据类型对象
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        //从redis中根据id获取商品详细信息的数据
        Object o = ops.get(EXCHANGDTAILE+id);
        //如果不存在，说明是第一次查询，可以先从数据库中拿到数据，这里需不需要设置过期时间，还需考虑
        if (o==null){
            forGoodsDetailVo=new ForGoodsDetailVo();
            //获取数据库的数据
            List<Map<String, Object>> maps = goodsMapper.selectByIdForGoods(id);
            //再创建一个List集合，方便存入GoodDetailVO对象
            List<Imgs> list=new ArrayList<>();
            //遍历，把数据加入到GoodDetailVO对象中
            for (Map<String, Object> map : maps) {
                Imgs img=new Imgs();
                //先添加简单类型的数据
                forGoodsDetailVo.setName(map.get("goods_name").toString());
                forGoodsDetailVo.setGoodsReferral(map.get("goods_referral").toString());
                forGoodsDetailVo.setGoodsDesc(map.get("goods_desc").toString());
                forGoodsDetailVo.setPrice(Double.valueOf(map.get("price").toString()));
                forGoodsDetailVo.setId(Long.valueOf(map.get("for_goods_id").toString()));
                forGoodsDetailVo.setExampleImg(map.get("example_img").toString());
                forGoodsDetailVo.setUsedEndTime(Timestamp.valueOf(map.get("used_end_time").toString()));
                //对VO的集合属性添加值
                img.setImg(map.get("img").toString());
                list.add(img);

            }
            //最后把list集合添加到VO对象中
            forGoodsDetailVo.setList(list);
            //把VO对象转化为json字符串
            String vo = JsonUtil.objectToString(forGoodsDetailVo);
            //添加到redis中
            ops.set(EXCHANGDTAILE+id,vo);
        }else {
            //如果redis中存在数据，获取信息
            Object o1 = ops.get(EXCHANGDTAILE + id);

            //转化为vo对象
            forGoodsDetailVo = JsonUtil.stringToObject(o1.toString(), ForGoodsDetailVo.class);

        }
        return forGoodsDetailVo;
    }

    @Override
    public void byExchangeGoods(Long id, Long userId) throws BusinessException {

        Map map = goodsMapper.selectStock(id);
        long total = Long.parseLong(map.get("for_goods_total").toString());
        if (total==0){
            throw new BusinessException(ExceptionCode.NO_STOCK);
        }
        BigDecimal price = BigDecimal.valueOf(Double.parseDouble(map.get("price").toString()));
        BigDecimal usefulGold = userGoldMapper.getUsefulGold(userId);
        int i = price.compareTo(usefulGold);
         if (i<0){
             throw new BusinessException(ExceptionCode.LOSS_MONEY);
         }
        UserExchange userExchange=new UserExchange();
        userExchange.setForGoodsId(id);
        userExchange.setForGoodsId(userId);
        userExchangeMapper.insert(userExchange);
    }
}
